﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using NUnit.Framework;
using Smith.AMC;
using Smith.AMC.Configuration;
using Smith.AMC.Network;


namespace MemcachedClientTests
{
    [TestFixture]
    public class ReplaceTest
    {
        private List<KeyValuePair<IPAddress, int>> servers = new List<KeyValuePair<IPAddress, int>>();


        [TestFixtureSetUp]
        public void PerTestSetUp()
        {
            servers.Add(new KeyValuePair<IPAddress, int>(IPAddress.Parse("127.0.0.1"), 11211));
        }

        [Test]
        public void ReplaceShouldReturnTrueIfItemIsReplaced()
        {
            ServerNodeMonitorConfiguration config = new ServerNodeMonitorConfiguration();
            ServerPool pool = new ServerPool(servers, SocketType.Stream, ProtocolType.Tcp, 25, config);
            MemcachedClient client = new MemcachedClient(new SocketWorker(pool, TimeSpan.FromSeconds(20)));

            ICacheItem<long> cacheItem = new CacheItem<long>
            {
                CacheKey = Guid.NewGuid().ToString(),
                LifeTime = TimeSpan.FromSeconds(0),
                Value = 1234567890
            };


            // Add an item first
            ManualResetEvent evt = new ManualResetEvent(false);
            bool cacheResponse = false;
            
            client.BeginAdd(
                cacheItem,
                ar =>
                {
                    ManualResetEvent evtInner = (ManualResetEvent)ar.AsyncState;
                    try
                    {
                        cacheResponse = client.EndAdd<long>(ar);
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e);
                    }
                    evtInner.Set();
                },
            evt);
            evt.WaitOne();


            ICacheItem<long> cacheItemReplace = new CacheItem<long>
            {
                CacheKey = cacheItem.CacheKey,
                LifeTime = TimeSpan.FromSeconds(0),
                Value = 123
            };


            
            ManualResetEvent evt2 = new ManualResetEvent(false);

            client.BeginReplace(
                cacheItemReplace,
                ar =>
                {
                    ManualResetEvent evtInner = (ManualResetEvent)ar.AsyncState;
                    try
                    {
                        cacheResponse = client.EndReplace<long>(ar);
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e);
                    }
                    evtInner.Set();
                },
            evt2);
            evt2.WaitOne();
            Assert.IsTrue(cacheResponse);
        }


        [Test]
        public void ReplaceShouldReturnFalseIfItemCouldNotBeReplaced()
        {
            ServerNodeMonitorConfiguration config = new ServerNodeMonitorConfiguration();
            ServerPool pool = new ServerPool(servers, SocketType.Stream, ProtocolType.Tcp, 25, config);
            MemcachedClient client = new MemcachedClient(new SocketWorker(pool, TimeSpan.FromSeconds(20)));

            ICacheItem<long> cacheItem = new CacheItem<long>
            {
                CacheKey = Guid.NewGuid().ToString(),
                LifeTime = TimeSpan.FromSeconds(0),
                Value = 1234567890
            };
            
            ManualResetEvent evt = new ManualResetEvent(false);
            bool cacheResponse = false;


            // Try to blindly replace an item
            client.BeginReplace(
                cacheItem,
                ar =>
                {
                    ManualResetEvent evtInner = (ManualResetEvent)ar.AsyncState;
                    try
                    {
                        cacheResponse = client.EndReplace<long>(ar);
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e);
                    }
                    evtInner.Set();
                },
            evt);
            evt.WaitOne();

            // Assert that replace failed
            Assert.IsFalse(cacheResponse);
        }

    }
}
